"""
chord.admin_api

Provides the Chord admin-server API.
"""
### Start of imports

# This line just better work...
from jackson import debug

# There's debug stuff for the rest
debug.pre_import(__name__)

debug.importing(__name__, 'settings from django.conf', 2)
from django.conf import settings

debug.importing(__name__, '* from exceptions')
from exceptions import *

debug.importing(__name__, 'core, db, net, sync from jackson.chord')
from jackson.chord import core, db, net, sync

debug.post_import(__name__)

### End of imports

def init_ring():
    """ Induces the server to provision itself as the first server of a new ring.
    @author: ep
    @rtype: True or False
    """
    context = [__name__, 'init_ring()']
    debug.enter(context, None)
    try:
        debug.comment(context, 'Clear out chord database')
        # Clear out the database
        core.clear_db()
        
        debug.comment(context, 'Constructing my finger')
        # Gather information about this server and create a finger for it.
        core.initialize_me()
        
        me = db.get_me()
        
        debug.comment(context, 'Initializing finger table')
        # Initialize my finger table - every entry should be me
        db.init_fingers(me)
        debug.comment(context, 'Finger table initialization complete')
        
        debug.comment(context, 'Activating')
        # Now I am provisioned
        db.update_status('A')
        
        debug.comment(context, 'Informing CDN of my key range')
        # Tell software using chord that it is now responsible for all keys
        core.trigger_add_keys_event(me.key, me.key, me)
        
        result = { 'me' : db.get_me()}
    except Exception, e:
        debug.exception(context, str(e))
        result = { 'exception' : str(e) }
    
    debug.leave(context, result)
    return result

def join_ring(server):
    """ Induces server to provision itself as a new server and issue a join request to the specified server.
    @author: ep
    @rtype: True or False
    """
    context = [__name__, 'join_ring()']
    debug.enter(context, { 'server' : server })
    try:
        debug.comment(context, 'Clear out chord database')
        # Clear out the database
        core.clear_db()

        debug.comment(context, 'Constructing my finger')
        # Gather information about this server and create a finger for it.
        core.initialize_me()

        me = db.get_me()
        debug.comment(context, "me = " + str(me))
        debug.comment(context, 'Initializing finger table')
        db.init_fingers(me)
        
        debug.comment(context, "Sending join request to the server we're joining")
        # Submit a join request to the given server
        welcome = net.join(server, me)
        
        # Check if join failed
        if not welcome:
            debug.comment(context, 'Did not receive welcome package')
            debug.leave(context, { 'success?' : False })
            return False

        debug.comment(context, 'Updating my successor and predecessor')
        # Aha, I am welcome!
        core.update_successor(welcome["successor"])
        core.update_predecessor(welcome["predecessor"])

        debug.comment(context, 'Initializing finger table with sync calls')
        # Initialize my finger table
        for k in range(2, settings.M + 1):
            sync.fix_one_finger(k)

        debug.comment(context, 'Finger table is complete')

        debug.comment(context, "Updating my predecessor's successor, and activating")
        # Now I am provisioned
        net.update_successor(welcome["predecessor"], me)
        core.update_status('A')

        debug.comment(context, 'Informing CDN of my key range')
        # Tell software using chord that it is now responsible for some keys.
        # @change: 3-14-09: core.trigger_add_keys_event(welcome["predecessor"].key, welcome["successor"].key, welcome["successor"])
        core.trigger_add_keys_event(welcome["predecessor"].key, me.key, welcome["successor"])

        result = { 'me' : db.get_me(), 'successor' : welcome['successor'], 'predecessor' : welcome['predecessor'] }
    except Exception, e:
        debug.exception(context, str(e))
        result = { 'exception in join_ring' : str(e) }
    
    debug.leave(context, result)
    return result

def leave_ring():
    """ Induces server to leave the ring it is currently joined to.
    @author: ep
    @rtype: True or False
    """
    context = [__name__, 'leave_ring()', []]
    debug.enter(context, None)
    try:
        debug.comment(context, 'Check that this server is active')
        # Assert that this server is active
        if not core.i_am_active():
            debug.exception(context, 'This server is not currently active')
            debug.leave(context, None)
            raise ChordServerNotActiveError
        
        # Gather some info
        me = db.get_me()
        
        # Change my status to Leaving
        core.update_status('L')
        
        # Notify my successor that I am leaving
        pred = core.get_predecessor()
        succ = core.get_successor()
        if not core.i_am(succ):
            debug.comment(context, 'Notifying successor that I am leaving')
            net.leave(succ, pred)
        
        debug.comment(context, 'Inform CDN that it is no longer responsible for any keys')
        # Tell software using chord that it is no longer responsible for some keys.
        core.trigger_del_keys_event(pred.key, me.key, succ)
        
        debug.comment(context, 'Deactivate')
        core.update_status('U')
        
        result = { 'success?' : True }
    except Exception, e:
        debug.exception(context, str(e))
        result = { 'exception' : str(e) }
    
    debug.leave(context, result)
    return result
